from Base import *
from Header import *

class CFuncCmdInfo(object):
    _gCmdNameDict={2:"Enable", 3:"Disable"}
    _gFunction = CONTROL_FUNCTION_NONE

    def __init__(self):
        self._successor=0

    def SetSuccessor(self, successor):
        self._successor=successor

    def AddInfoImp(self, funcCmdEle):
        item = funcCmdEle._subList[funcCmdEle._gNameFuncCmd]
        cmd = funcCmdEle._cmd
        if cmd in self._gCmdNameDict:
            item._infoStr = self._gCmdNameDict[funcCmdEle._cmd]
        else:
            item._errStr = "Invalid command"


    def AddInfo(self, funcCmdEle):
        if funcCmdEle._function == self._gFunction:
            self.AddInfoImp(funcCmdEle)
        else:
            if self._successor != 0:
                self._successor.AddInfo(funcCmdEle)

class CFuncCmdInfoMil(CFuncCmdInfo):
    _gFunction = CONTROL_FUNCTION_MIL

class CFuncCmdInfoMan(CFuncCmdInfo):
    _gFunction = CONTROL_FUNCTION_MAN

class CFuncCmdInfoAlm(CFuncCmdInfo):
    _gFunction = CONTROL_FUNCTION_ALM

class CFuncCmdInfoSvt(CFuncCmdInfo):
    _gCmdNameDict={2:"Start Tracking", 3:"Stop Tracking"}
    _gFunction = CONTROL_FUNCTION_SVT


class CFuncCmdInfoRdc(CFuncCmdInfo):
    _gCmdNameDict={2:"Lock", 3:"UnLock"}
    _gFunction = CONTROL_FUNCTION_RDC

class CFuncCmdInfoSpd(CFuncCmdInfo):
    _gCmdNameDict={3:"Cancel Speed Alert"}
    _gFunction = CONTROL_FUNCTION_SPD
    _gMaskSpdId = 0x0F

    def AddInfoImp(self, funcCmdEle):
        super(CFuncCmdInfoSpd, self).AddInfoImp(funcCmdEle)

        item = funcCmdEle._subList[funcCmdEle._gNamePara]
        para = funcCmdEle._para
        if len(para) != 1:
            item._errStr = "Invalid para"
        else:
            temp = para[0]
            id = temp & self._gMaskSpdId
            item._infoStr = "Id is <" + DATA_FORMAT.format(id) + ">"

class CFuncCmdInfoGeo(CFuncCmdInfo):
    _gCmdNameDict={3:"Cancel Geo Fence"}
    _gFunction = CONTROL_FUNCTION_GEO
    _gMaskGeoId = 0x0F
    _gMaskGeoType = 0xF0
    _gTypeDict={0:"Inclusion", 1:"Exclusion"}

    def AddInfoImp(self, funcCmdEle):
        super(CFuncCmdInfoGeo, self).AddInfoImp(funcCmdEle)

        item = funcCmdEle._subList[funcCmdEle._gNamePara]
        para = funcCmdEle._para
        if len(para) != 1:
            item._errStr = "Invalid para"
        else:
            temp = para[0]
            subItem = item.CreateSubItem("Geo-Fence Type")
            type = (temp & self._gMaskGeoType) > 4
            subItem._rawStr = DATA_FORMAT.format(type)
            if type in self._gTypeDict:
                subItem._infoStr = self._gTypeDict[type]
            else:
                subItem._errStr = "Invalid Type"

            subItem = item.CreateSubItem("Geo-Fence ID")
            id = temp & self._gMaskGeoId
            subItem._rawStr = DATA_FORMAT.format(id)





#this function is responsibile to set chain well to avoid bad loop
def AddFuncCmdResponseChain(fn):
    def new(self,*args):
        fcDefault = CFuncCmdInfo()

        fcSvt = CFuncCmdInfoSvt()
        fcSvt.SetSuccessor(fcDefault)

        fcRdc = CFuncCmdInfoRdc()
        fcRdc.SetSuccessor(fcSvt)

        fcSpd = CFuncCmdInfoSpd()
        fcSpd.SetSuccessor(fcRdc)

        fcGeo = CFuncCmdInfoGeo()
        fcGeo.SetSuccessor(fcSpd)

        fcMil = CFuncCmdInfoMil()
        fcMil.SetSuccessor(fcGeo)

        fcMan = CFuncCmdInfoMan()
        fcMan.SetSuccessor(fcMil)

        fcAlm = CFuncCmdInfoAlm()
        fcAlm.SetSuccessor(fcMan)

        return fn(self, successor=fcAlm)
    return new

class CFunctionCommandElement(CInfoElement):
    _gName = "Function Command Element"
    _gNameFuncCmd = "Function Command"
    _gNameSubHd = "Sub Head"
    _gNamePara = "Parameter"

    @AddFuncCmdResponseChain
    def __init__(self, name=_gName, successor=0):
        super(CFunctionCommandElement, self).__init__(name)
        self._cmd = -1
        #parameter may have more than 1 byte
        self._para= []

        #cmd information is different depend on control function
        self._function=0

        #this is response chain, it's used to add different informantion
        #depend on different control function type
        self._successor = successor

        self._hlColor = 'white_on_blue'

    def SetFunction(self, function):
        self._function = function

    def InitSubItem(self):
        name = self._gNameHeader
        item = CEleHeader(name)
        self._subList[name] = item
        self._nameList.append(name)

        self.CreateSubItem(self._gNameFuncCmd)

        #self.CreateHeader(self._gNameSubHd)  #paramter has a element header format, which indicates lengths of parameter2
        name = self._gNameSubHd
        item = CEleHeader(name)
        self._subList[name] = item
        self._nameList.append(name)

        self.CreateSubItem(self._gNamePara)

    def ParseElement(self, dataStr):
        self._cmd = dataStr.GetByte()
        item = self._subList[self._gNameFuncCmd]
        item._rawStr = HEX_DATA_FORMAT.format(self._cmd)

        #parameter is in format of element header
        subHd = self._subList[self._gNameSubHd]
        subHd.Parse(dataStr)

        item = self._subList[self._gNamePara]
        startIx = dataStr.GetIndex()
        len = subHd.GetLength()
        for i in range(0, len):
            byte = dataStr.GetByte()
            self._para.append(byte)
        paraStr = dataStr.GetString(startIx, startIx+len)
        item._rawStr = DATA_STRING_FORMAT.format(paraStr)


        if self._successor != 0:
            self._successor.AddInfo(self)

        return


